package com.wxb.shmily.util;

import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.util.*;

/**
 * Created by shmily on 2017/6/27.
 */
public class SignUtil {
    /**
     * 编码
     */
    private static String ENCODE = "utf-8";

    //public static Logger log = Logger.getLogger(SignUtil.class);

    /**
     * MD5加密处理
     *
     * @param src
     * @return
     */
	/*public final static String MD5LowerCase( String src ) {

		StringBuffer buf = new StringBuffer("");

		try {
			// 获取MD5摘要算法对象
			MessageDigest digest = MessageDigest.getInstance( "MD5" );

			// 使用指定的字节更新摘要
			digest.update( src.getBytes( ENCODE ) );

			// 获取密文
			byte[] b = digest.digest();

			// 将密文转换成16进制的字符串形式
			int i = 0;

			for ( int offset = 0; offset < b.length; offset++ ) {

				i = b[offset];
				if ( i < 0 ) i += 256;
				if ( i < 16 ) buf.append( "0" );
				buf.append( Integer.toHexString(i) );
			}

		} catch ( Exception e ) {
			e.printStackTrace();
			return "";
		}
		return buf.toString();
	}*/

    /**
     * map 转换成 根据 key 排序的  v1v2v3 连接的字符串
     *
     * @param params
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String mapToValueStringSortAsc( Map<String, String> params ) {

        List<String> valList = Arrays.asList( params.keySet().toArray( new String[params.size()] ) );
        Collections.sort(valList);

        StringBuilder sb = new StringBuilder();
        for ( String k : valList ) {
            // 跳过 不被签名参数
            if ( k.equals( "sign" ) || StringUtils.isBlank(k) || StringUtils.isBlank(params.get(k))) {
                continue;
            }else{
                sb.append(params.get(k));
            }
        }

        return sb.toString();
    }


    /**
     * map 转换成 根据 key 排序的  key=value&key=value 字符串
     * @param params
     * @return
     */
    public static String mapToKeyValueSortAsc( Map<String, String> params ) {
        List<String> valList = Arrays.asList( params.keySet().toArray( new String[params.size()] ) );
        Collections.sort(valList);

        StringBuilder info = new StringBuilder();
        for ( String k : valList ) {
            // 跳过 不被签名参数
            if ( k.equals( "sign" ) || StringUtils.isBlank(k) || StringUtils.isBlank(params.get(k))) {
                continue;
            }else{
                info.append(k+"="+params.get(k)+"&");
            }
        }

        String s = info.toString();
        if(s.length() == 0){
            return s;
        }else{
            return s.substring(0, s.length() -1 );
        }
    }

    /**
     * k1=v1&k2=v2&k3=v3 的串转换成  map
     * @param str
     * @return
     */
    public static Map<String, String> keyValueToMap(String str){
        Map<String, String> map = new HashMap<String, String>();
        String[] temp = str.split("&");
        for (int i = 0; i < temp.length; i++) {
            if(StringUtils.isBlank(temp[i])){
                continue;
            }
            String[] key = temp[i].split("=");
            if(key == null || key.length < 2){
                continue;
            }

            map.put(key[0], key[1]);
        }

        return map;
    }

    /**
     * request 参数对应封装到  c 当中
     * @param request
     * @param c
     * @return
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public static <T> T requestToBean(HttpServletRequest request, Class<T> c)
            throws IllegalArgumentException, IllegalAccessException, InstantiationException{

        T bean = c.newInstance();
        Field[] fields = c.getDeclaredFields();
        Field.setAccessible(fields, true);

        for (int i = 0; i < fields.length; i++) {
            Field fi = fields[i];
            String name = fi.getName();
            fi.set(bean, request.getParameter(name));
        }

        return bean;
    }

    /**
     * request 中的所有数据转换成普通可以使用的map。<br/>
     * 1、有key但 value是 null，会赋值成 "" <br/>
     * 2、如果  value 是数组，会将数组的所有元素通过 ',' 进行连接。
     * @param request
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static Map<String, String> requestToMap(HttpServletRequest request) {
        // 返回值Map
        Map<String, String> returnMap = new HashMap<String, String>();

        // 参数Map
        Map<?, ?> properties = request.getParameterMap();
        Iterator<?> entries = properties.entrySet().iterator();
        Map.Entry entry;
        String name = "";
        String value = "";
        while (entries.hasNext()) {
            entry = (Map.Entry) entries.next();
            name = (String) entry.getKey();
            Object valueObj = entry.getValue();
            if(null == valueObj){
                value = "";
            }else if(valueObj instanceof String[]){
                String[] values = (String[])valueObj;
                for(int i=0;i<values.length;i++){
                    value = values[i] + ",";
                }
                value = value.substring(0, value.length()-1);
            }else{
                value = valueObj.toString();
            }
            returnMap.put(name, value);
        }
        return returnMap;
    }

    /**
     * 根据给定的 bean fields 生成按 key 字母顺序排列的  key, value 的map。
     * @param bean  给定的 bean
     * @param containList 包含的字段（空参表示所有字段）
     * @param excluList   强制不包含的字段（空参表示没有强制不包含的字段）
     * @return
     * @throws IllegalAccessException
     * @throws IllegalArgumentException
     */
    public static Map<String, String> getFieldsMap(Object bean, boolean isAddEmptyField, String[] containList, String[] excluList) {
        Map<String, String> map = new TreeMap<String, String>();

        try{
            Class<? extends Object> c = bean.getClass();
            Field[] fields = c.getDeclaredFields();
            Field.setAccessible(fields, true);

            List<String> cl = new ArrayList<String>();
            if(containList != null){
                cl = Arrays.asList(containList);
            }

            List<String> exl = new ArrayList<String>();
            if(excluList != null){
                exl = Arrays.asList(excluList);
            }

            for (int i = 0; i < fields.length; i++) {
                Field fi = fields[i];

                String value = fi.get(bean) == null ? null : fi.get(bean).toString();
                String name = fi.getName();

                if( (cl.isEmpty() || cl.contains(name)) && !exl.contains(name)){
                    if(value != null || (value == null && isAddEmptyField)){
                        map.put(fi.getName(), value); //值为空的时候，只有  isAddEmptyField = true 时会加入到 map 当中
                    }
                }
            }

            return map;
        }catch (Exception e) {
            //log.info("获取映射出错", e);
            return map;
        }
    }

    /**
     * 对某个 bean 当中的非空参数进行加密
     * @param bean
     * @param md5key
     * @return
     */
    public static String signBean(Object bean, String md5key){
        Map<String, String> map = getFieldsMap(bean, false, null, null);
        String signStr = mapToKeyValueSortAsc(map);
        return DigestUitl.MD5LowerCase(signStr + md5key);
    }

    public static void main( String[] args ) {

        try {
			/*OrderBean bean = new OrderBean();
			bean.setCardNo("334214324");
			bean.setMobile("13500000000");

			Map<String, String> map = getFieldsMap(bean, false, null, null);*/
            Map<String, String> map = new HashMap<>();
            //对 map里面的 key-values 进行签名
            String s  =mapToKeyValueSortAsc(map);
            String sign = DigestUitl.MD5LowerCase(s+"p4V7LIH8iwFWhUgHZVqn3vZCLvosqlIZ");
            System.out.println(s+" sign="+sign);


            Map<String, String> map2 = keyValueToMap(s);
            System.out.println(s);
            System.out.println(map2);

        } catch ( Exception e ) {

            e.printStackTrace();
        }

    }
}
